#ifndef F_CPU
#define F_CPU 8000000UL
#endif

#include "tacho.h"

#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint8_t HR_COUNTER0;         // High Register for Timer/Counter0
volatile uint16_t tacho_period;       // Measured rotation period
volatile uint32_t tacho_averaged;
volatile uint16_t  tacho_nb_pulse;
volatile uint8_t tacho_got_pulse;     // Flag for acquired pulse

ISR(TIMER0_OVF_vect) {
  // Increment the High Register on TCNT0 overflow
  HR_COUNTER0++;
}

ISR(TACHO_INT_VECT) {

  static uint16_t t_last;
  uint16_t t_now = (((uint16_t) HR_COUNTER0 << 8) | TCNT0);
  uint16_t diff = t_now - t_last;

  if ((diff<6700)&&(diff>150)) {
    tacho_period = diff;
    tacho_averaged += (uint32_t) diff;
    tacho_nb_pulse++;

    t_last = t_now;
    tacho_got_pulse = 1;
  }

}

void set_pin_int(void){
  
  TACHO_MSK |= _BV(TACHO_PIN);

}

void clear_pin_int(void){
  
  TACHO_MSK &= ~(_BV(TACHO_PIN));

}

void tacho_init(void) {

  /*** Timer 0 Settings ***/

  /* 8 prescaler for 2MHz clock */
  TCCR0B |= _BV(CS01);
  /* Enable Timer Overflow Interrupts */
  TIMSK0 |= _BV(TOIE0);
  /* Set counters to 0 */
  HR_COUNTER0 = 0;
  TCNT0 = 0;

  /*** Pin interrupt settings ***/
  TACHO_PORT |= _BV(ISC00);
  set_pin_int();


  /*** Variables initialization ***/
  tacho_nb_pulse = 0;
  tacho_got_pulse = 0;

}

int tacho_get_rpm(void) {

  clear_pin_int();

  static uint32_t ret_last;
  const uint32_t tacho_to_rpm = 2000000*60/TACHO_NB_SLOTS;
  uint32_t tacho, ret;

  if (tacho_nb_pulse)
    tacho = tacho_averaged/tacho_nb_pulse;
  else
    tacho = 0;
  
  if (tacho==0)
    ret = 0;
  else
    ret = tacho_to_rpm/tacho;
  
  tacho_averaged = 0;
  tacho_nb_pulse = 0;

  ret = ret_last/ALPHA_DEN*ALPHA_NUM + ret/ALPHA_DEN*(ALPHA_DEN-ALPHA_NUM);
  ret_last = ret;

  set_pin_int();

  return ret;

}
